/**
 * 
 */
package com.golden.gamedev.engine.timer;

import java.io.Serializable;

import com.golden.gamedev.ActionExecutor;
import com.golden.gamedev.Refreshable;

/**
 * The {@link SerializableTimer} class provides a {@link Serializable}
 * implementation of the {@link Timer} interface, with the restriction that its
 * {@link ActionExecutor} delegate must be {@link Serializable}.<br />
 * <br />
 * For convenience, the provided {@link Timer} implementations in GTGE are also
 * {@link ActionExecutor} instances which delegate their
 * {@link ActionExecutor#execute() execution} to their configured
 * {@link ActionExecutor} instance. <br />
 * <br />
 * Currently, the {@link SerializableTimer} class is extendable due to
 * maintaining backwards compatibility, however, it is not suitable for
 * extension. All methods, therefore, have been marked as final, and the
 * {@link SerializableTimer} class will itself be marked as final in 0.2.5.
 * 
 * @author MetroidFan2002
 * @version 1.0
 * @since 0.2.4
 * @see Timer
 * @see Refreshable
 * @see Serializable
 * @see ActionExecutor
 */
public class SerializableTimer implements Timer, Refreshable, Serializable,
        ActionExecutor {
	
	/**
	 * {@link Serializable} ID generated by Eclipse.
	 */
	private static final long serialVersionUID = 1L;
	
	/**
	 * The non-null {@link TimerDelegate} instance to actually perform the
	 * tracking of the state of the {@link Timer} interface implementation.
	 */
	private final TimerDelegate delegate;
	
	/**
	 * The non-null {@link Serializable} {@link ActionExecutor} instance to use
	 * to {@link ActionExecutor#execute() execute} an action before
	 * {@link #action(long)} returns true.
	 */
	private final ActionExecutor executor;
	
	/**
	 * Creates a new {@link SerializableTimer} instance with the specified delay
	 * time in milliseconds and the non-null {@link Serializable}
	 * {@link ActionExecutor} instance to invoke immediately before
	 * {@link #action(long)} returns true.
	 * @param delay The delay time, in milliseconds.
	 * @param executor The non-null {@link ActionExecutor} instance to invoke
	 *        immediately before {@link #action(long)} returns true.
	 * @throws IllegalArgumentException Throws an
	 *         {@link IllegalArgumentException} if the given
	 *         {@link ActionExecutor} instance is not {@link Serializable}.
	 */
	public SerializableTimer(long delay, final ActionExecutor executor) {
		super();
		if (!(executor instanceof Serializable)) {
			throw new IllegalArgumentException(
			        "The ActionExecutor instance must be Serializable "
			                + "because this Timer instance is Serializable.");
		}
		this.delegate = new TimerDelegate(delay);
		this.executor = executor;
	}
	
	public final boolean action(long elapsedTime) {
		if (delegate.action(elapsedTime)) {
			executor.execute();
			return true;
		}
		return false;
	}
	
	/**
	 * Refreshs the timer counter (current tick).
	 * @deprecated This method is deprecated in favor of {@link #reset()} and
	 *             will be removed in 0.2.5.
	 */
	public final void refresh() {
		delegate.reset();
	}
	
	/**
	 * Makes this timer state equals with other timer, this include active
	 * state, delay time, and timer current tick.
	 * @deprecated This method has been renamed to {@link #copy(Timer)} and now
	 *             returns the current {@link Timer} instance to support
	 *             chaining. This method will be removed in 0.2.5
	 */
	public final void setEquals(Timer other) {
		delegate.setActive(other.isActive());
		delegate.setDelay(other.getDelay());
		delegate.setCurrentTick(other.getCurrentTick());
	}
	
	public final Timer copy(final Timer toCopy) {
		setEquals(toCopy);
		return this;
	}
	
	/**
	 * *************************************************************************
	 */
	/**
	 * ************************ TIMER VARIABLES ********************************
	 */
	/**
	 * *************************************************************************
	 */
	
	public final boolean isActive() {
		return this.delegate.isActive();
	}
	
	public final void setActive(boolean b) {
		this.delegate.setActive(b);
	}
	
	public final long getDelay() {
		return this.delegate.getDelay();
	}
	
	public final void setDelay(long i) {
		this.delegate.setDelay(i);
	}
	
	public final long getCurrentTick() {
		return this.delegate.getCurrentTick();
	}
	
	/**
	 * Sets timer current tick.
	 * <p>
	 * 
	 * If current tick is exceeded timer {@linkplain #getDelay() delay time},
	 * the {@linkplain #action(long) action(elapsedTime)} method will return
	 * true.
	 * @deprecated This method is deprecated with no direct replacement and will
	 *             be removed in 0.2.5 - code should not attempt to set the
	 *             current tick value directly, instead, rely on the
	 *             {@link #action(long)} method to set the value appropriately -
	 *             {@link #reset()} may also be invoked to set this value to 0.
	 */
	public final void setCurrentTick(long tick) {
		this.delegate.setCurrentTick(tick);
	}
	
	public final void reset() {
		refresh();
	}
	
	public final void execute() {
		executor.execute();
	}
	
}
